/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.ControlEscolar.Services;

import com.ControlEscolar.Exceptions.*;
import com.ControlEscolar.Beans.GroupDetail;
import com.ControlEscolar.Beans.Enrollment;
import com.ControlEscolar.DAOs.DAOException;
import com.ControlEscolar.DAOs.EnrollmentDAO;
import com.ControlEscolar.DAOs.StudentDAO;
import com.ControlEscolar.Validations.ValidationEnrollment;
import com.ControlEscolar.Validations.ValidationExam;
import com.ControlEscolar.Validations.ValidationStudent;
import java.util.ArrayList;



/**
 *
 * @author Rodna Marrufo
 */
public class EnrollmentService {
    EnrollmentDAO enrolmentDAO=new EnrollmentDAO();
    StudentDAO studentDAO=new StudentDAO();
    GroupService groupService=new GroupService();
    ValidationExam validationExam=new ValidationExam();
    ValidationEnrollment validationEnrollment=new ValidationEnrollment();
    ValidationStudent validationStudent=new ValidationStudent();


    private final int FIRS_ENROLMENT=1;
    private final int REENROLMENT=2;
    private final int REVALIDATION=3;


    public ArrayList<GroupDetail> getGroupsToEnrol(String studentKey, int semester, int ID_Curriculum, int enrolmentType)
            throws ServiceExp,  //error of db
            EnrollmentExp,   //error in erolment
            TypeEnrolmentExp, //incorrect type of inscription
            IncompleteDocumentsExp, //incomple document
            FailedSubjectsExp,      //subject fail
            FailedReenrollmentSemesterExp,  //when u enroll twice a failed semester
            SemesterExp,  //jump semester
            ExtraordinaryExp,  // when u fail more than 3 exordinary exam
            NotFailedSubjectsExp, //when u enrol a semester which u already passed
            DropStudentExp  
            {
        try {
            if (mayEnrol(studentKey, semester, ID_Curriculum, enrolmentType)) {
                return groupService.getGroupsDetailToStudent(ID_Curriculum, semester, studentKey);
            }
            throw new EnrollmentExp("Error al Inscribir el alumno");
        } catch (DAOException ex) {
            throw new ServiceExp();
        }
    }

    public void  enrolStudent(ArrayList<Enrollment>enrolmentsSubjects, int typeEnrolment) throws ServiceExp, AlreadyExistExp, IncorrectSubjectExp{
        try {
            Enrollment enrollment = enrolmentsSubjects.get(0);
            String studentKey=enrollment.getStudentKey();
             ArrayList<String> subjectKeys=getSubjectsFromEnrollments(enrolmentsSubjects);
          if(validationEnrollment.isEnrollRightSubjects(subjectKeys, enrollment.getID_Curriculum(), enrollment.getSemester())){
            updateAcademicInfo(typeEnrolment,studentKey);
                for (int index = 0; index < enrolmentsSubjects.size(); index++) {
                    enrollment = enrolmentsSubjects.get(index);
                    System.out.println(enrollment);
                    enrolmentDAO.add(enrollment);
            }
          }
          else
             throw new IncorrectSubjectExp("MATERIAS INCORRECTAS");

        } catch (DAOException ex) {
            throw new ServiceExp();
        }
    }

    private ArrayList<String> getSubjectsFromEnrollments(ArrayList<Enrollment>enrolmentsSubjects){
        ArrayList<String> subjectKeys=new ArrayList();
        for(int index=0;index<enrolmentsSubjects.size();index++){
            subjectKeys.add(enrolmentsSubjects.get(index).getSubjectKey());
        }
        return subjectKeys;

    }

     public void toDropStudent(String studentKey) throws ServiceExp, NotExistStudentExp{
        try {
                studentDAO.disableState(studentKey);
        } catch (DAOException ex) {
           throw new ServiceExp();
        }
    }

    private boolean mayEnrol(String studentKey, int semester, int ID_Curriculum, int enrolmentType) throws ServiceExp, DAOException, TypeEnrolmentExp, IncompleteDocumentsExp, FailedSubjectsExp, FailedReenrollmentSemesterExp, SemesterExp, ExtraordinaryExp, NotFailedSubjectsExp, DropStudentExp{
        if(!validationStudent.isDropStudent(studentKey)){
           switch(enrolmentType){
               case FIRS_ENROLMENT:
                   return canEnrolFirstTime(studentKey, ID_Curriculum);
               case REENROLMENT:
                   return canReenrolment(studentKey, ID_Curriculum, semester);
               case REVALIDATION:
                   return canRevalidation(studentKey, ID_Curriculum);
               default:
                   return false;
           }
        }
        else
            throw new DropStudentExp("estas dado de baja");
       
   }

   private boolean canEnrolFirstTime(String studentKey, int ID_Curriculum) throws DAOException, TypeEnrolmentExp, IncompleteDocumentsExp {
            if (validationEnrollment.isStudentFirstEnroll(studentKey, ID_Curriculum)) {
                if (validationEnrollment.isDocumentsComplete(studentKey))
                    return true;
                else throw new IncompleteDocumentsExp("No tiene la Documentacion Completa");
            }
            else throw new TypeEnrolmentExp("Tipo de inscripcion Invalido");
   }

   private boolean canRevalidation(String studentKey, int ID_Curriculum) throws DAOException, TypeEnrolmentExp, IncompleteDocumentsExp{
            if (validationEnrollment.isStudentRevalidation(studentKey, ID_Curriculum)) {
                if (validationEnrollment.isDocumentsComplete(studentKey))
                    return true;
                else throw new IncompleteDocumentsExp("No tiene la Documentacion Completa");
            }
            else throw new TypeEnrolmentExp("Tipo de inscripcion Invalido");
   }


   private boolean canReenrolment(String studentKey, int ID_Curriculum, int semesterToEnroll) throws DAOException, FailedSubjectsExp, NotFailedSubjectsExp, FailedReenrollmentSemesterExp, ExtraordinaryExp, TypeEnrolmentExp, SemesterExp{
       final int HIGHEST_SEMESTER=2;
       final int EQUAL_SEMESTER=0;

       if(validationEnrollment.isStudentEnrolled(studentKey, ID_Curriculum)){
          int semesterType=validationEnrollment.semesterComparator(semesterToEnroll, studentKey);
          switch(semesterType){
              case HIGHEST_SEMESTER:
                  return canEnrolHighestSemester(studentKey, ID_Curriculum, semesterToEnroll);
              case EQUAL_SEMESTER:
                  return canEnrolmentSameSemester(studentKey, ID_Curriculum, semesterToEnroll);
              default:
                  return canEnrolmentLowestFirst_Semester(studentKey, ID_Curriculum, semesterToEnroll);
          }
       }
       else throw new TypeEnrolmentExp("Tipo de inscripcion Invalido");
   }


   private boolean canEnrolHighestSemester(String studentKey, int ID_Curriculum, int semester) throws DAOException, FailedSubjectsExp, FailedReenrollmentSemesterExp, SemesterExp{
       if(!validationEnrollment.isFailedReenrollmentSemester(studentKey, beforeSemester(semester), ID_Curriculum)){
            if(validationEnrollment.isEnrolledSemester(studentKey, beforeSemester(semester), ID_Curriculum)){
                if(validationEnrollment.passedMinimunOfSubjects(studentKey, ID_Curriculum, beforeSemester(semester))){
                    if(validationEnrollment.isEnrollingSecondSemester(semester))
                        return true;
                    else{
                        if(validationEnrollment.isFailedSubjects(studentKey, ID_Curriculum, yearAgoSemester(semester)))
                            throw new FailedSubjectsExp("Reprobo materias, no se puede inscribir");
                        else return true;
                    }
                }
                else throw new FailedSubjectsExp("Reprobo materias, no se podra inscribir");
           }
            else throw new SemesterExp("Fallo en el Semestre");
       }
       else throw new FailedReenrollmentSemesterExp("Fallo en la inscripcion al Semestre");
   }

  private boolean validationReenrolmentFailedSemester(String studentKey, int ID_Curriculum, int semester) throws DAOException,NotFailedSubjectsExp, FailedReenrollmentSemesterExp, ExtraordinaryExp{
      if(validationEnrollment.isFailedSubjects(studentKey, ID_Curriculum, semester)){
         if(!validationEnrollment.isFailedReenrollmentSemester(studentKey, semester, ID_Curriculum)){
             if(!validationExam.isFailedMaxExtra(studentKey, ID_Curriculum, semester))
                 return true;
             else throw new ExtraordinaryExp("Reprobo Tres Extraordinarios");
         }

         else throw new FailedReenrollmentSemesterExp("Fallo en la inscripcion al Semestre");
     }
     else throw new NotFailedSubjectsExp("No reprobo Materias");
  }

private boolean canEnrolmentLowestFirst_Semester(String studentKey, int ID_Curriculum, int semester) throws DAOException, NotFailedSubjectsExp, FailedReenrollmentSemesterExp, ExtraordinaryExp{
    return validationReenrolmentFailedSemester(studentKey, ID_Curriculum, semester);
}

private boolean canEnrolmentSameSemester(String studentKey, int ID_Curriculum, int semester) throws DAOException, NotFailedSubjectsExp, FailedReenrollmentSemesterExp, ExtraordinaryExp, FailedSubjectsExp{
   if(validationEnrollment.isFailedSubjects(studentKey, ID_Curriculum, beforeSemester(semester))){
       throw new FailedSubjectsExp("debo materias del semestre anterior");
   }
   else{
       if( validationReenrolmentFailedSemester(studentKey, ID_Curriculum, semester)){
           if(!validationEnrollment.isFailedReenrollmentSemester(studentKey, beforeSemester(semester), ID_Curriculum)){
             if(!validationExam.isFailedMaxExtra(studentKey, ID_Curriculum, beforeSemester(semester)))
                 return true;
             else throw new ExtraordinaryExp("Reprobo Tres Extraordinarios");
            }
        
         else throw new FailedReenrollmentSemesterExp("Fallo en la inscripcion al Semestre");
     }
       else return false;
   }
         
   
}

   private int beforeSemester(int semester){
       int beforeSemester=semester-1;
       return beforeSemester;
   }
    private int yearAgoSemester(int semester){
       int yearAgoSemester=semester-1;
       return yearAgoSemester;
   }
  
    private void updateAcademicInfo(int typeEnrolment, String studentKey) throws DAOException{
        if(typeEnrolment==REENROLMENT){
            disableBeforeEnrolments(studentKey);
        }
        else{
            if(typeEnrolment==REVALIDATION)
                studentDAO.disableRevalidationStatus(studentKey);
        }
   }
    
   private void disableBeforeEnrolments(String studentKey) throws DAOException{
      enrolmentDAO.disableStudentEnrollment(studentKey);

   }


}
